package shi_redis

import (
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"github.com/go-redis/redis"
	"io"
	"math"
	"strconv"
)

type GeoRedisKey struct {
	Key       string  `json:"key"`
	Member    string  `json:"member"`
	Longitude float64 `json:"longitude"`
	Latitude  float64 `json:"latitude"`
}

type GeoStruc struct {
	Longitude float64 `json:"longitude"` //经度
	Latitude  float64 `json:"latitude"`  //纬度
	Radius    float64 `json:"radius"`    //半径
	Unit      string  `json:"unit"`      //km or m
	Count     int     `json:"count"`     //入选参数
	Sort      string  `json:"sort"`      //排序
	Member    string  `json:"member"`
}

//初始化数据
func GeoInit(GeoStrucmod *GeoStruc) *GeoStruc {
	geo := new(GeoStruc)
	geo.Longitude = GeoStrucmod.Longitude
	geo.Latitude = GeoStrucmod.Latitude
	geo.Radius = GeoStrucmod.Radius
	geo.Member = GeoStrucmod.Member
	if geo.Radius <= 0 {
		geo.Radius = 5
	}
	geo.Unit = GeoStrucmod.Unit
	geo.Count = GeoStrucmod.Count
	if geo.Count == 0 {
		geo.Count = 5
	}
	geo.Sort = GeoStrucmod.Sort
	if len(geo.Sort) <= 0 {
		geo.Sort = "ASC"
	}
	return geo
}

var Redis *redis.Client

var Keys = "Sicily"

//redis链接
func RedisCon(Addr string, Password string, DB int, Key string) *redis.Client {
	Redis = redis.NewClient(&redis.Options{
		Addr:     Addr,
		Password: Password, // no password set
		DB:       DB,
	})
	//定义一个key
	if len(Key) > 0 {
		Keys = Key
	}

	return Redis
}

//添加
func AddRedis(Menber string, Longitude float64, Latitude float64) error {
	 _,err:=Redis.GeoAdd(Keys, &redis.GeoLocation{
		Name:      Menber,
		Longitude: Longitude,
		Latitude:  Latitude,
	}).Result()

	return err
}

//获取位置
func Geopos(Menber string) (interface{},error) {
	list, err := Redis.GeoPos(Keys, Menber).Result()
	return list,err
}

//返回俩位置间的距离 unit:km or m
func Geodist(Menberone string, Menbertwo string, unit string) (float64,error) {
	dist, err := Redis.GeoDist(Keys, Menberone, Menbertwo, unit).Result()
	return dist,err
}

//返回以经纬度为中心半径范围内的坐标点
func Georadius(GeoStruc *GeoStruc) (interface{},error) {
	GeoStruc = GeoInit(GeoStruc)
	resRadiu, err := Redis.GeoRadius(Keys, GeoStruc.Longitude, GeoStruc.Latitude, &redis.GeoRadiusQuery{
		Radius:      GeoStruc.Radius, //radius表示范围距离，
		Unit:        GeoStruc.Unit,   //距离单位是 m|km|ft|mi
		WithCoord:   true,            //传入WITHCOORD参数，则返回结果会带上匹配位置的经纬度
		WithDist:    true,            //传入WITHDIST参数，则返回结果会带上匹配位置与给定地理位置的距离。
		WithGeoHash: true,            //传入WITHHASH参数，则返回结果会带上匹配位置的hash值。
		Count:       GeoStruc.Count,  //入COUNT参数，可以返回指定数量的结果。
		Sort:        GeoStruc.Sort,   //默认结果是未排序的，传入ASC为从近到远排序，传入DESC为从远到近排序。
	}).Result()

	return resRadiu,err
}

//返回以位置为中心半径范围内的坐标点
func Georadiusbymember(GeoStruc *GeoStruc) (interface{},error) {
	GeoStruc = GeoInit(GeoStruc)

	GeoRadiusByMember, err := Redis.GeoRadiusByMember(Keys, GeoStruc.Member, &redis.GeoRadiusQuery{
		Radius:      GeoStruc.Radius, //radius表示范围距离，
		Unit:        GeoStruc.Unit,   //距离单位是 m|km|ft|mi
		WithCoord:   true,            //传入WITHCOORD参数，则返回结果会带上匹配位置的经纬度
		WithDist:    true,            //传入WITHDIST参数，则返回结果会带上匹配位置与给定地理位置的距离。
		WithGeoHash: true,            //传入WITHHASH参数，则返回结果会带上匹配位置的hash值。
		Count:       GeoStruc.Count,  //入COUNT参数，可以返回指定数量的结果。
		Sort:        GeoStruc.Sort,   //默认结果是未排序的，传入ASC为从近到远排序，传入DESC为从远到近排序。
	}).Result()

	return GeoRadiusByMember,err
}

//生成Guid字串
func UniqueId() string {
	b := make([]byte, 48)

	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return GetMd5String(base64.URLEncoding.EncodeToString(b))
}

//生成32位md5字串
func GetMd5String(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}

//返回俩位置间的距离
func Geodistance(Lng1 float64, Lat1 float64, Lng2 float64, Lat2 float64) (string,error) {
	keys := UniqueId()
	Key := keys

	err:=AddRedis("Key"+"1", Lng1, Lat1)

	err=AddRedis("Key"+"2", Lng1, Lat1)
	if err!=nil {
		return "0",err
	}

	dist, _ := Redis.GeoDist(Key, "Key"+"1", "Key"+"2", "").Result()
	var Distance string
	if dist < 1 {

		dist = dist * 1000
		distNew := FormatFloat(dist, 2)
		//diststr:=strconv.FormatFloat(dist, 'f', -1, 64)
		Distance = distNew + "m"
	} else {
		//diststr:=strconv.FormatFloat(dist, 'f', -1, 64)
		distNew := FormatFloat(dist, 2)
		Distance = distNew + "km"
	}
	//Geo地图功能
	//清除数据
	 DeleteToKey(Key)

	return Distance,nil
}

//通过关键之删除redis
func Delete() (int64,error) {
	num, err := Redis.Del(Keys).Result()
	if err != nil {
		return -1,err
	}
	return num,err

}

//通过关键之删除redis
func DeleteToKey(Key string) (int64,error) {
	num, err := Redis.Del(Key).Result()
	if err != nil {
		return -1,err
	}
	return num,err

}

//取小数点
func FormatFloat(num float64, decimal int) string {
	// 默认乘1
	d := float64(1)
	if decimal > 0 {
		// 10的N次方
		d = math.Pow10(decimal)
	}
	// math.trunc作用就是返回浮点数的整数部分
	// 再除回去，小数点后无效的0也就不存在了
	return strconv.FormatFloat(math.Trunc(num*d)/d, 'f', -1, 64)
}
